CodeCommitレポジトリ作成時に指定のブランチに特定のファイルを作るカスタムリソースを作成してみた
こんにちは!AWS事業本部コンサルティング部のたかくに(@takakuni_)です。
突然ですが、 CodeCommit レポジトリ作成時に自動でREADME.md
を作りたくなった経験ありますか?私はアリます。
今回は、CloudFormationカスタムリソースでリポジトリ作成時にREADME.md
を作ってみようと思います。
はじめに
すでに作成されているのでは?と思い探したところ、CloudFormationマクロを使用して同じようなことをしているコードが見つかりました。
私自身のスキルセットの問題ですが、CloudFormationマクロ以前にカスタムリソースもあまり作ってこなかったため、今回はカスタムリソースでの実装に挑戦してみました。
コード
完成したコードが以下になります。
AWSTemplateFormatVersion: '2010-09-09'
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "General Configuration"
Parameters:
- RepositoryName
- BranchName
- FilePath
- FileContent
Parameters:
RepositoryName:
Type: String
Description: "Enter the name of the repository"
Default: "test-repo"
BranchName:
Type: String
Description: "Enter the name of the branch where you want to store README.md"
Default: "main"
FilePath:
Type: String
Description: "Enter the name of the file"
Default: "README.md"
FileContent:
Type: String
Description: "Enter the contents of the README.md"
Default: "Hello, World"
Resources:
#################################
# CodeCommit Repository
#################################
Repository:
Type: AWS::CodeCommit::Repository
Properties:
RepositoryName: !Ref RepositoryName
#################################
# Custom Resource
#################################
PutReadMeRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Path: /
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
- "arn:aws:iam::aws:policy/AWSCodeCommitPowerUser"
PutReadMeLog:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub "/aws/lambda/${RepositoryName}-${BranchName}-put-readme"
PutReadMeFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub "${RepositoryName}-${BranchName}-put-readme"
Code:
ZipFile: |
import json
import boto3
import cfnresponse
def handler(event, context):
try:
repository = event['ResourceProperties']['RepositoryName']
branch = event['ResourceProperties']['BranchName']
content = event['ResourceProperties']['FileContent'].encode()
path = event['ResourceProperties']['FilePath']
if event['RequestType'] == 'Create':
codecommit = boto3.client('codecommit')
response = codecommit.put_file(
repositoryName=repository,
branchName=branch,
fileContent=content,
filePath=path,
commitMessage='Initial Commit',
name='Your Lambda Helper'
)
cfnresponse.send(event, context, cfnresponse.SUCCESS, response)
if event['RequestType'] == 'Delete':
cfnresponse.send(event, context, cfnresponse.SUCCESS, {'Response': 'Success'})
if event['RequestType'] == 'Update':
cfnresponse.send(event, context, cfnresponse.SUCCESS, {'Response': 'Success'})
except Exception as e:
print(e)
cfnresponse.send(event, context, cfnresponse.FAILED, {})
Handler: index.handler
MemorySize: 128
Role: !GetAtt PutReadMeRole.Arn
Runtime: "python3.9"
Timeout: 60
Tags:
- Key: "Name"
Value: !Sub "${RepositoryName}-${BranchName}-put-readme"
DependsOn: PutReadMeLog
PutReadMe:
Type: Custom::CodeCommitPutReadMe
Properties:
ServiceToken: !GetAtt PutReadMeFunction.Arn
RepositoryName: !GetAtt Repository.Name
BranchName: !Ref BranchName
FileContent: !Ref FileContent
FilePath: !Ref FilePath
マネジメントコンソールから確認
では、実際に動作確認を行い作成されているか確認してみます。
今回は以下の値を入力して作成しました。
設定値 | 値 | 備考 |
---|---|---|
スタックの名前 | codecommit-readme | |
RepositoryName | codecommit-readme | |
BranchName | dev | |
FilePath | README.md | |
FileContent | Hello, World |
CodeCommitレポジトリを確認すると、問題なく指定したブランチにREADME.md
が作成されていました。
気をつけたこと
ただ、「完成したコードはこちらで、動作確認も問題ないです」だと味気ないので、実装で詰まった点や考慮した点をご紹介します。
DependsOnを使って依存関係
CloudFormationスタック削除時に、ログも消えるように設定したかったため、PutReadMeLog(AWS::Logs::LogGroup)
とPutReadMeFunction(AWS::Lambda::Function)
にDependsOn
を使用して依存関係を設定しました。
もしログを残したい場合は、DeletionPolicy: Retain
を使用してください。
スタックの削除時は以下の順序で削除が行われます。
- PutReadMe(Custom::CodeCommitPutReadMe)
- PutReadMeFunction(AWS::Lambda::Function)
- PutReadMeLog(AWS::Logs::LogGroup)
cfn-responseモジュール
cfn-response モジュールは、カスタムリソースとLambda関数間で応答するためのモジュールとして使用されます。
注意する点は、以下ブログのとおり、応答メソッドをリクエストタイプごとに実装する必要があります。
この分岐処理が実装されていない場合、Delete
やUpdate
時に応答メソッドがないために、カスタムリソースがIN_PROGRESS
のままで止まってしまう可能性があります。
おわりに
以上、「CodeCommitレポジトリ作成時に指定のブランチに特定のファイルを作るカスタムリソースを作成してみた」でした。
今回はカスタムリソースで実装してみましたが、今後はCloudFormationマクロや拡張機能にも挑戦してみようと思いました。
この記事がどなたかのご参考になれば幸いです。
以上、AWS事業本部コンサルティング部のたかくに(@takakuni_)でした!